#include "Triangle.h"
#include <string>

Triangle::Triangle(std::ifstream& inputFile){
	position[3] = 1.f;
	position2[3] = 1.f;
	position3[3] = 1.f;
	
	normalVector[3] = 0.f;
	std::string textureFile;
	
	inputFile >> name >> position[0] >> position[1] >> position[2];
	//inputFile >> normalVector[0] >> normalVector[1] >> normalVector[2];
	inputFile >> position2[0] >> position2[1] >> position2[2];
	inputFile >> position3[0] >> position3[1] >> position3[2];
	inputFile >> color.r >> color.g >> color.b;
	inputFile >> ambienceConstant >> diffusionConstant >> specularConstant;
	inputFile >> reflectionConstant >> specularExponent;
	inputFile >> transparency >> refractionIndex;
	inputFile >> textureFile;
	
	if(textureFile.compare("none") != 0)
		texture.readImage(textureFile);
	
	// Find edges of triangle
	edge1 = position3-position2;
	edge2 = position2-position;
	
	// Find normal vector
	normalVector = edge1.cross(edge2);
	normalVector.normalize();
	
	
	// FROM PLANE
	distance = position.magnitude();
}

Vector Triangle::normal(Vector &surfacePoint){
	return normalVector;
}

std::vector<double> Triangle::intersection(Ray& ray){
	std::vector<double> results;

	// FROM PLANE
	double Vd = normalVector.dotProduct(ray.direction);
	if(Vd < -doubleResolution || Vd > doubleResolution){// A solution exists
		double t = -1 * (normalVector.dotProduct(ray.initialPoint) + distance)/Vd;
		if(t > doubleResolution){
			// Check if point is inside the triangle
			Vector point;
			point[3] = 1.f;
			point[0] = ray.initialPoint[0]+t*ray.direction[0];
			point[1] = ray.initialPoint[1]+t*ray.direction[1];
			point[2] = ray.initialPoint[2]+t*ray.direction[2];
			if(contains(point)) {
				results.push_back(t);
			}
		}
	}
	return results;
	
}

bool Triangle::contains(Vector& point){
	//return normalVector.dotProduct(point - position) < -doubleResolution;
	
	// FROM:
	// http://softsurfer.com/Archive/algorithm_0105/algorithm_0105.htm#Segment-Plan
	// u=edge1, v=edge2
	float    uu, uv, vv, wu, wv, D;
	uu = edge1.dotProduct(edge1);
    uv = edge1.dotProduct(edge2);
    vv = edge2.dotProduct(edge2);
    w = point - position;
    wu = w.dotProduct(edge1);
    wv = w.dotProduct(edge2);
    D = uv*uv - uu*vv;

    // get and test parametric coords
    float s, t;
    s = (uv * wv - vv * wu) / D;
    if (s < 0.0 || s > 1.0)        // outside
        return false;
    t = (uv * wu - uu * wv) / D;
    if (t < 0.0 || (s + t) > 1.0)  // outside
        return false;

    return true;                      // inside
}

Color Triangle::getColor(Vector& position){
	Color value = color;
	
	if(texture.hasTexture()) {
		// set the axis for the plane
		Vector UAxis = Vector(normalVector[1], normalVector[2], -normalVector[0], normalVector[3]);
		Vector VAxis = UAxis.cross(normalVector);
		
		// find the coordinates on the plane
		double u = position.dotProduct(UAxis);
		double v = position.dotProduct(VAxis);
		value = texture.GetPixel(u,v)*color;
	}
		
	return value;
	
}
